<?php
/**
 * 文件操作类
 *
 * @author seraph.liujb 2009.4.28
 */
/*
 $params = array(
 //服务器名
 'host'=>'http://img01.domain.com/',
 //根目录
 'dir'=>ROOT_PATH . '/public/temp/',
 //应用模块名称
 'name'=>'user',
 );
 $f = Common_File::factory('Abstract',$params);
 //设置服务器名
 //        $f->setHost('http://image.idkin.com/');
 //设置根目录
 //        $f->setDir('../public/');
 //设置应用模块名称
 //        $f->setName('user');
 //设置目录分割数列，默认为array(2,2,3)
 //        $f->setExplode(array(3,3,3));
 //设置关闭目录分割，默认为true打开
 //        $f->isExplode(false);
 //强制指定目标文件名，默认为自动处理为源文件名附加随机数串
 //        $f->setDestFilename('ssss.jpg');

 $f->create(ROOT_PATH . '/public/temp/01.jpg');
 //获取处理后的目标文件绝对路径
 var_dump($f->getDestFile());
 var_dump(file_exists($f->getDestFile()));
 //获取处理后的目标文件URL相对路径，如设置host则返回URL绝对路径
 var_dump($f->getDestFileUrl());

 var_dump($f);
 */

class Common_File_Abstract
{
    /**
     * @var $_host 所在服务器名称
     * @var $_dir 文件处理目录名称
     * @var $_name 文件处理类型名称
     * @var $_path 文件存储目录名称，一般为绝对路径，在运行时生成
     */
    protected  $_host = '';
    protected $_dir = '';
    protected $_name = 'DefaultFile';
    protected $_path = '';
    
    /**
     * @var $_sourFile 目标文件，全路径名称
     * @var $_destFilename 目标文件名
     */
    protected $_sourFile = '';
    protected $_destFilepath = '';
    protected $_destFilename = '';
        
    /**
     * @var $_explode 文件分布路径的分割数列
     * @var $_isExplode 是否进行分割处理
     */
    protected $_explode = array(2,2,3);
    protected $_isExplode = true;
    
    /**
     * __construct
     *
     * @param array $params
     * host 所在服务器名称，例：http://img01.domain.com/
     * dir 文件处理目录名，一般用来指定相对根目录，所有文件处理都在该目录及其子目录内
     * name 文件处理类型名称，不同的应用模块使用不同的名称，如：user company
     * explode 文件名所生成分布路径的分割数列，默认为：2,2,3
     */
    public function __construct($params = array())
    {
        //初始化
        $this->setParams($params);
        if (is_null($params['dir'])) {
                $this->_dir = ROOT_PATH . '/public/';
        }
        //生成默认文件处理根路径
        $this->setPath();
    }
    
    /**
     * 设置配置参数
     *
     * @param array $params
     * @return boolean
     */
    public function setParams($params = array())
    {
        if (!is_array($params)) {
            throw new Exception('$params必须是数组类型！');
        }
        foreach ($params as $paramsName=>$paramsValue) {
            $paramsName = '_' . $paramsName;
            if(isset($this->$paramsName)) {
                $this->$paramsName=$paramsValue;
            }
            else {
                throw new Exception("属性{$paramsName}未定义！");
            }
        }
        return true;
    }
    
    /**
     * setHost
     *
     * @param string $host
     * @return Common_File_Abstract
     */
    public function setHost($host)
    {
        /* @todo 设置文件存入的服务器名，为远程文件操作预留 */
        $this->_host = $host;
        return $this;
    }
    
    /**
     * setDir
     *
     * @param string $dir
     * @return Common_File_Abstract
     */
    public function setDir($dir)
    {
        $this->_dir = $dir;
        $this->setPath();
        return $this;
    }
    
    /**
     * setName
     *
     * @param string $name
     * @return Common_File_Abstract
     */
    public function setName($name)
    {
        $this->_name = $name;
        $this->setPath();
        return $this;
    }
    
    /**
     * 重设文件处理根路径，ROOT_PATH . dir . name
     * 
     * @return Common_File_Abstract
     */
    private function setPath()
    {
        $this->_path = $this->_dir . $this->_name . '/';
        return $this;
    }
    
    /**
     * 获取目标文件路径
     *
     * @return string
     */
    public function getDestFilepath()
    {
        //如果存在则直接返回
        if ('' == $this->_destFilepath) {
            //是否生成分割目录
            if ($this->_isExplode) {
                $result = Common_String::explodeStringFromArray(md5($this->getDestFilename()),$this->_explode);
            }
            else {
                $result = '';
            }
            $this->_destFilepath = $this->_name . '/' . $result;
        }
        return $this->_destFilepath;
    }
    
    /**
     * 设置目标文件名
     *
     * @param string $filename
     * @return Common_File_Abstract
     */
    public function setDestFilename($filename)
    {
        $this->_destFilename = $filename;
        return $this;
    }
    
    /**
     * 获取目标文件名，如未设置，则从来源文件名进行计算，md5($this->_sourFile . microtime())
     *
     * @return string
     */
    public function getDestFilename()
    {
        //如果已经设置_destFilename，直接返回
        if ('' == $this->_destFilename) {
            //生成目标文件名称
            $pathinfo = pathinfo($this->getSourFile());
            $this->_destFilename = $pathinfo['filename'] . '-' . intval(microtime(true)) . '.' . $pathinfo['extension'];
        }
        return $this->_destFilename;
    }
    
    /**
     * 设置来源文件名
     *
     * @param string $filename
     * @return Common_File_Abstract
     */
    public function setSourFile($filename)
    {
        $this->_sourFile = $filename;
        return $this;
    }
    public function getSourFile()
    {
        return $this->_sourFile;
    }
    
    /**
     * 设置文件名分布路径的分割数列
     *
     * @param array $explode
     * @return Common_File_Abstract
     */
    public function setExplode($explode)
    {
        $this->_explode = $explode;
        return $this; 
    }
    
    /**
     * 设置是否进行目录分割处理，默认为true
     *
     * @param boolean $isExplode
     * @return Common_File_Abstract
     */
    public function isExplode($isExplode = true)
    {
        $this->_isExplode = $isExplode;
        return $this;
    }
    
    /**
     * 建立或复制新文件到指定位置
     *
     * @param string $sour 来源文件全路径
     * @return boolean
     */
    public function create($sour)
    {
        //判断来源文件有效
        if (!file_exists($sour)) {
            throw new Exception('来源文件不存在！' . $sour);
        }
        if (!is_readable($sour)) {
            throw new Exception('来源文件没有读取权限！' . $sour);
        }
        //设置来源文件全路径名称
        $this->setSourFile($sour);
        //获取目标文件全路径名称
        $dest = $this->_dir . $this->getDestFilepath() . $this->getDestFilename();
        //确认目录有效
        $this->checkUploadDir(dirname($dest));
        //复制
        return @copy($sour,$dest);
    }
    
    /**
     * 获取目标文件绝对路径
     *
     * @return string
     */
    public function getDestFile()
    {
        return $this->_dir . $this->getDestFilepath() . $this->getDestFilename(); 
    }
    
    /**
     * 获取目标文件URL地址，绝对路径
     *
     * @return string
     */
    public function getDestFileUrl()
    {
        return $this->_host . '/' . $this->getDestFilepath() . $this->getDestFilename(); 
    }
        
    /**
     * 删除文件
     *
     * @param string $file 指定文件全路径名，或目录全路径名
     * @return boolean
     */
    public function delete($file)
    {
        //判断文件是否存在
        if (file_exists($file) && !is_dir($file)) {
            return @unlink($file);
        }
        else {
            return false;
        }
    }
    
    /**
     * 读取指定文件内容
     *
     * @param string $file 来源文件全路径
     * @return string
     */
    public function read($file)
    {
        //判断来源文件有效
        if (!file_exists($file)) {
            throw new Exception('来源文件不存在！' . $file);
        }
        if (!is_readable($file)) {
            throw new Exception('来源文件没有读取权限！' . $file);
        }
        //打开
    	$f = fopen($file,'r');
    	$result = fread($f,filesize($file));
    	return $result;
    }
    
	/**
     * 写入指定文件，覆盖重写
     *
     * @param string $file 目标文件路径
     * @param string $context 写入内容
     * @return int
     */
	public function write($file, $context = '')
    {
		if(file_exists($file)){
			if(is_file($file)){
				if (!is_writable($file)){
					throw new Exception("文件" . $file . "没有写入权限!",0);
					return false;
				}
				$f = fopen($file,'w');
				$result = fwrite($f,$context);
				return $result;
			}else {
				throw new Exception($file . '是一个目录',0);
				return false;
			}
		}else {
			if(basename($file)){
				$this->checkUploadDir(dirname($file));
				$f = fopen($file.'w');
				$result = fwrite($f,$context);
				fclose($f);
				return $result;
			}else {
				throw new Exception($file . '是一个目录',0);
				return false;
			}
		}
    }
    
    
    /**
     * 校验与自动生成指定文件路径，根路径默认存在、有权、可写
     *
     * @param string $dir_path 需校验的目录
     * @return boolean
     */
    public function checkUploadDir($dirpath)
    {
    	if(!is_dir($dirpath)){
    		$this->checkUploadDir(dirname($dirpath));
    		@mkdir($dirpath,0777);
    	}else{
    		return true;
    	}
    }
    
    /**
     * 建立目录
     *
     * @param string $dirname 需要建立的目录
     * @return boolean
     */
    public function createDir($dirname)
    {
        return $this->checkUploadDir($dirname);
    }
    
    /**
     * 删除目录，可判断是否为空目录
     *
     * @param string $dirname 需删除的目录
     * @param boolean $checkDirHaveFile 是否判断目录为空，默认为true
     * @return boolean
     */
    public function deleteDir($dirname, $checkDirHaveFile = true)
    {
        //判断是否目录
        if (is_dir($dirname)) {
            //判断目录是否为空
            if ($checkDirHaveFile && $this->checkDirHaveFile($dirname)) {
                return false;
            }
            else {
                return rmdir($dirname);
            }
        }
        else {
            return false;
        }
    }
    
    /**
     * 判断目录内是否有文件或其它目录
     *
     * @param unknown_type $dirname
     * @return unknown
     */
    private function checkDirHaveFile($dirname)
    {
        $dir =dir($dirname);
        while (false != $filename = $dir->read()) {
            if ('.' != $filename && '..' != $filename) {
                return true;
            }
        }
        return false;
    }
}
